home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / Source / Chapter 13 / Game / PlayerObject.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-10-01  |  25.3 KB  |  762 lines

  1. //-----------------------------------------------------------------------------
  2. // PlayerObject.h implementation.
  3. // Refer to the PlayerObject.h interface for more details.
  4. //
  5. // Programming a Multiplayer First Person Shooter in DirectX
  6. // Copyright (c) 2004 Vaughan Young
  7. //-----------------------------------------------------------------------------
  8. #include "Main.h"
  9.  
  10. //-----------------------------------------------------------------------------
  11. // The player object class constructor.
  12. //-----------------------------------------------------------------------------
  13. PlayerObject::PlayerObject( PlayerInfo *player, Script *script, unsigned long type ) : AnimatedObject( script->GetStringData( "mesh_name" ), script->GetStringData( "mesh_path" ), type )
  14. {
  15.     // Set the player's DirectPlay ID.
  16.     m_dpnid = player->dpnid;
  17.  
  18.     // Set the players's name.
  19.     m_name = new char[strlen( player->name ) + 1];
  20.     strcpy( m_name, player->name );
  21.  
  22.     // Players start with full health;
  23.     m_health = 100.0f;
  24.     m_dying = false;
  25.  
  26.     // Indicate that the view transform is not being taken from this player.
  27.     m_isViewing = false;
  28.  
  29.     // Clear the player's score.
  30.     m_frags = 0;
  31.     m_deaths = 0;
  32.  
  33.     // Player objects start off invisible and disabled.
  34.     SetVisible( false );
  35.     SetEnabled( false );
  36.  
  37.     // Clear the player's input.
  38.     m_drive = 0.0f;
  39.     m_strafe = 0.0f;
  40.     m_fire = false;
  41.  
  42.     // Set the correct ellipse radius.
  43.     SetEllipsoidRadius( *script->GetVectorData( "ellipse_radius" ) );
  44.  
  45.     // Level the player's view tilt.
  46.     m_viewTilt = 0.0f;
  47.  
  48.     // Set the default view smoothing and sensitivity.
  49.     m_viewSmoothing = 0.5f;
  50.     m_viewSensitivity = 0.5f;
  51.  
  52.     // Get the view weapon offset.
  53.     m_viewWeaponOffset = *script->GetVectorData( "view_weapon_offset" );
  54.  
  55.     // Clear the weapons array.
  56.     for( unsigned char w = 0; w < 10; w++ )
  57.         m_weapons[w] = NULL;
  58.  
  59.     // The player starts with the first basic weapon.
  60.     Script *weaponScript = new Script( "Gun1.txt", "./Assets/Objects/Gun1/" );
  61.     m_weapons[0] = new Weapon( weaponScript, m_viewWeaponOffset );
  62.     m_currentWeapon = 0;
  63.     if( player->dpnid == g_engine->GetNetwork()->GetLocalID() )
  64.         m_weapons[m_currentWeapon]->UseViewWeapon( true );
  65.     else
  66.         m_weapons[m_currentWeapon]->UseViewWeapon( false );
  67.     SAFE_DELETE( weaponScript );
  68.  
  69.     // Indicate that the player is not changing weapons.
  70.     m_changingWeapon = 0.0f;
  71.     m_weaponChanging = false;
  72.  
  73.     // Create the callback data used for tracking the player's foot steps.
  74.     m_callbackData[0].foot = 0;
  75.     m_callbackData[1].foot = 1;
  76.  
  77.     // Create the callback keys. The second key time is set per animation.
  78.     D3DXKEY_CALLBACK keys[2];
  79.     keys[0].Time = 0;
  80.     keys[0].pCallbackData = &m_callbackData[0];
  81.     keys[1].pCallbackData = &m_callbackData[1];
  82.  
  83.     LPD3DXKEYFRAMEDANIMATIONSET oldAS;
  84.     LPD3DXCOMPRESSEDANIMATIONSET newAS;
  85.     LPD3DXBUFFER buffer;
  86.  
  87.     // Go through the four movement animations and set the foot step keys.
  88.     for( char a = 1; a < 5; a++ )
  89.     {
  90.         // Get the old animation.
  91.         GetAnimationController()->GetAnimationSet( a, (LPD3DXANIMATIONSET*)&oldAS );
  92.  
  93.         // Set the time for the second key.
  94.         keys[1].Time = float( oldAS->GetPeriod() / 2.0f * oldAS->GetSourceTicksPerSecond() );
  95.  
  96.         // Compress the old animation set.
  97.         oldAS->Compress( D3DXCOMPRESS_DEFAULT, 0.4f, NULL, &buffer );
  98.  
  99.         // Create the new animation using the old one and the foot step keys.
  100.         D3DXCreateCompressedAnimationSet( oldAS->GetName(), oldAS->GetSourceTicksPerSecond(), oldAS->GetPlaybackType(), buffer, 2, keys, &newAS );
  101.         SAFE_RELEASE( buffer );
  102.  
  103.         // Unregister the old animation set.
  104.         GetAnimationController()->UnregisterAnimationSet( oldAS );
  105.         SAFE_RELEASE( oldAS );
  106.  
  107.         // Register the new animation set.
  108.         // Note: The new animation is appended to the end of the list.
  109.         GetAnimationController()->RegisterAnimationSet( newAS );
  110.         SAFE_RELEASE( newAS );
  111.     }
  112.  
  113.     // Play the idle animation.
  114.     PlayAnimation( 0, 0.0f );
  115.  
  116.     // Create the step sound audio paths.
  117.     m_leftStepAudioPath = new AudioPath3D;
  118.     m_rightStepAudioPath = new AudioPath3D;
  119.  
  120.     // Set the friction on this object.
  121.     SetFriction( 8.0f );
  122. }
  123.  
  124. //-----------------------------------------------------------------------------
  125. // The player object class destructor.
  126. //-----------------------------------------------------------------------------
  127. PlayerObject::~PlayerObject()
  128. {
  129.     // Destroy the weapons array.
  130.     for( unsigned char w = 0; w < 10; w++ )
  131.         SAFE_DELETE( m_weapons[w] );
  132.  
  133.     // Destroy the string buffer containing the player's name.
  134.     SAFE_DELETE( m_name );
  135. }
  136.  
  137. //-----------------------------------------------------------------------------
  138. // Updates the player object.
  139. //-----------------------------------------------------------------------------
  140. void PlayerObject::Update( float elapsed, bool addVelocity )
  141. {
  142.     // Allow the base animated object to update.
  143.     AnimatedObject::Update( elapsed, addVelocity );
  144.  
  145.     // Override the object's forward vector to take the view tilt into account.
  146.     // This will allow the forward vector to move up and down as well instead
  147.     // of just remaining horizontal. This is not important for movement since
  148.     // the player can not fly, but for things like shooting it is.
  149.     m_forward.x = (float)sin( GetRotation().y );
  150.     m_forward.y = (float)-tan( m_viewTilt );
  151.     m_forward.z = (float)cos( GetRotation().y );
  152.     D3DXVec3Normalize( &m_forward, &m_forward );
  153.  
  154.     // Set the player's view point. This is done every frame because as the
  155.     // mesh is animated, the reference point in the mesh may move. This
  156.     // will allow the view point to move with the mesh's animations.
  157.     m_viewPoint = GetMesh()->GetReferencePoint( "rp_view_point" )->GetTranslation();
  158.  
  159.     // Ensure that the view movement is relative to the rotation.
  160.     D3DXVec3TransformCoord( &m_viewPoint, &m_viewPoint, GetRotationMatrix() );
  161.  
  162.     // Only calculate the correct view matrix if it is being used.
  163.     if( m_isViewing == true )
  164.     {
  165.         // Create the x axis rotation matrix.
  166.         D3DXMATRIX rotationXMatrix;
  167.         D3DXMatrixRotationX( &rotationXMatrix, m_viewTilt );
  168.  
  169.         // Create the combined rotation matrix (i.e. y axis rotation from the
  170.         // scene object plus the x axis rotation from the player object).
  171.         D3DXMATRIX combinedRotation;
  172.         D3DXMatrixMultiply( &combinedRotation, &rotationXMatrix, GetRotationMatrix() );
  173.  
  174.         // Build a translation matrix that represents the final view point.
  175.         D3DXMATRIX viewPointTranslationMatrix;
  176.         D3DXVECTOR3 finalViewPointTranslation = GetTranslation() + m_viewPoint;
  177.         D3DXMatrixTranslation( &viewPointTranslationMatrix, finalViewPointTranslation.x, finalViewPointTranslation.y, finalViewPointTranslation.z );
  178.  
  179.         // Override the object's view matrix using the combined rotation and
  180.         // the position of the final view point translation.
  181.         D3DXMatrixMultiply( &m_viewMatrix, &combinedRotation, &viewPointTranslationMatrix );
  182.         D3DXMatrixInverse( &m_viewMatrix, NULL, &m_viewMatrix );
  183.     }
  184.  
  185.     // Ignore the rest if the player is dying (or dead)
  186.     if( m_dying == true )
  187.         return;
  188.  
  189.     // Drive and strafe the player accordingly.
  190.     if( m_drive != 0.0f )
  191.         Drive( m_drive * 8000.0f * elapsed );
  192.     if( m_strafe != 0.0f )
  193.         Strafe( m_strafe * 4000.0f * elapsed );
  194.  
  195.     // Update the step audio paths.
  196.     m_leftStepAudioPath->SetPosition( GetTranslation() + GetMesh()->GetReferencePoint( "rp_left_foot" )->GetTranslation() );
  197.     m_leftStepAudioPath->SetVelocity( GetVelocity() );
  198.     m_rightStepAudioPath->SetPosition( GetTranslation() + GetMesh()->GetReferencePoint( "rp_right_foot" )->GetTranslation() );
  199.     m_rightStepAudioPath->SetVelocity( GetVelocity() );
  200.  
  201.     // Check if the player is changing their weapon (local player only).
  202.     static float move = 0.0f;
  203.     if( m_changingWeapon > 0.0f )
  204.     {
  205.         m_changingWeapon -= elapsed;
  206.  
  207.         if( m_changingWeapon > 1.0f )
  208.         {
  209.             // Lower the old weapon.
  210.             move -= 100.0f * elapsed;
  211.             m_weapons[m_oldWeapon]->RaiseLowerWeapon( elapsed, this, move );
  212.         }
  213.         else if( m_changingWeapon < 0.0f )
  214.         {
  215.             // The new weapon is in place.
  216.             m_changingWeapon = 0.0f;
  217.             move = 0.0f;
  218.  
  219.             // Send a message to inform the other players the weapon is ready.
  220.             PlayerWeaponChangeMsg pwcm;
  221.             pwcm.msgid = MSGID_PLAYER_WEAPON_CHANGE;
  222.             pwcm.dpnid = g_engine->GetNetwork()->GetLocalID();
  223.             pwcm.weapon = m_currentWeapon;
  224.             g_engine->GetNetwork()->Send( &pwcm, sizeof( PlayerWeaponChangeMsg ), DPNID_ALL_PLAYERS_GROUP, DPNSEND_NOLOOPBACK );
  225.         }
  226.         else
  227.         {
  228.             // Raise the new weapon.
  229.             move += 100.0f * elapsed;
  230.             m_weapons[m_currentWeapon]->RaiseLowerWeapon( elapsed, this, move );
  231.         }
  232.     }
  233.     else
  234.     {
  235.         // Update the player's current weapon, when not changing weapons.
  236.         if( m_weaponChanging == false )
  237.             m_weapons[m_currentWeapon]->Update( elapsed, m_fire, this, m_viewPoint.y );
  238.     }
  239. }
  240.  
  241. //-----------------------------------------------------------------------------
  242. // Renders the player object.
  243. //-----------------------------------------------------------------------------
  244. void PlayerObject::Render( D3DXMATRIX *world )
  245. {
  246.     // Allow the base animated object to render.
  247.     if( m_dpnid != g_engine->GetNetwork()->GetLocalID() )
  248.         AnimatedObject::Render( world );
  249.     else if( m_dying == true )
  250.         return;
  251.  
  252.     // Render the player's weapon.
  253.     if( m_weaponChanging == false )
  254.     {
  255.         if( m_changingWeapon > 1.0f )
  256.             m_weapons[m_oldWeapon]->Render( this );
  257.         else
  258.             m_weapons[m_currentWeapon]->Render( this );
  259.     }
  260. }
  261.  
  262. //-----------------------------------------------------------------------------
  263. // Called when something collides with the object.
  264. //-----------------------------------------------------------------------------
  265. void PlayerObject::CollisionOccurred( SceneObject *object, unsigned long collisionStamp )
  266. {
  267.     // Ignore collisions if the player is dying (or dead)
  268.     if( m_dying == true )
  269.         return;
  270.  
  271.     // Allow the base scene object to register the collision.
  272.     SceneObject::CollisionOccurred( object, collisionStamp );
  273.  
  274.     // Check if the player has hit a spawner object.
  275.     if( object->GetType() != TYPE_SPAWNER_OBJECT )
  276.         return;
  277.  
  278.     // Get a pointer to the spawner object.
  279.     SpawnerObject *spawner = (SpawnerObject*)object;
  280.  
  281.     // Check if the player has picked up a weapon.
  282.     if( *spawner->GetObjectScript()->GetNumberData( "type" ) == WEAPON_SPAWN_OBJECT )
  283.     {
  284.         // Get the list position of the weapon.
  285.         char listPosition = (char)*spawner->GetObjectScript()->GetNumberData( "list_position" );
  286.  
  287.         // Ensure the player doesn't already have a weapon in this slot.
  288.         if( m_weapons[listPosition] == NULL )
  289.         {
  290.             // Load the new weapon in.
  291.             m_weapons[listPosition] = new Weapon( spawner->GetObjectScript(), m_viewWeaponOffset );
  292.  
  293.             // Check if this is the local player.
  294.             if( m_dpnid == g_engine->GetNetwork()->GetLocalID() )
  295.             {
  296.                 // Set the weapon to use the first person mesh.
  297.                 m_weapons[listPosition]->UseViewWeapon( true );
  298.  
  299.                 // Change to this weapon.
  300.                 ChangeWeapon( 0, listPosition );
  301.             }
  302.             else
  303.             {
  304.                 // Set the weapon to use the first person mesh.
  305.                 m_weapons[listPosition]->UseViewWeapon( false );
  306.             }
  307.         }
  308.         else if( m_weapons[listPosition]->GetValid() == false )
  309.         {
  310.             // Validate the weapon.
  311.             m_weapons[listPosition]->SetValid( true );
  312.  
  313.             // Change to this weapon.
  314.             ChangeWeapon( 0, listPosition );
  315.         }
  316.     }
  317. }
  318.  
  319. //-----------------------------------------------------------------------------
  320. // Rotates the player's view.
  321. //-----------------------------------------------------------------------------
  322. void PlayerObject::MouseLook( float x, float y, bool reset )
  323. {
  324.     static float lastX = 0.0f;
  325.     static float lastY = 0.0f;
  326.  
  327.     // Check if the player's view needs to be reset.
  328.     if( reset == true )
  329.     {
  330.         lastX = lastY = 0.0f;
  331.         SetRotation( 0.0f, 0.0f, 0.0f );
  332.         m_viewTilt = 0.0f;
  333.         return;
  334.     }
  335.  
  336.     // Calculate the real x and y values by accounting for smoothing.
  337.     lastX = lastX * m_viewSmoothing + x * ( 1.0f - m_viewSmoothing );
  338.     lastY = lastY * m_viewSmoothing + y * ( 1.0f - m_viewSmoothing );
  339.  
  340.     // Adjust the values for sensitivity.
  341.     lastX *= m_viewSensitivity;
  342.     lastY *= m_viewSensitivity;
  343.  
  344.     // Rotate the scene object around the y axis only. This will prevent the
  345.     // player's mesh from rotating when the player looks up and down.
  346.     AddRotation( 0.0f, lastY, 0.0f );
  347.  
  348.     // Ensure the view will not rotate to far up or down.
  349.     if( ( m_viewTilt > 0.8f && lastX > 0.0f ) || ( m_viewTilt < -0.8f && lastX < 0.0f ) )
  350.         lastX = 0.0f;
  351.  
  352.     // Maintain a seperate view rotation around the x axis to allow the player
  353.     // to look up and down.
  354.     m_viewTilt += lastX;
  355. }
  356.  
  357. //-----------------------------------------------------------------------------
  358. // Hurts the player with the given damage.
  359. //-----------------------------------------------------------------------------
  360. void PlayerObject::Hurt( float damage, PlayerObject *attacker )
  361. {
  362.     // Ignore dying (or dead) players.
  363.     if( m_dying == true )
  364.         return;
  365.  
  366.     // Adjust the player's health.
  367.     m_health -= damage;
  368.  
  369.     // Send a player health update message.
  370.     PlayerHealthMsg phm;
  371.     phm.msgid = MSGID_PLAYER_HEALTH;
  372.     phm.dpnid = m_dpnid;
  373.     phm.health = m_health;
  374.     g_engine->GetNetwork()->Send( &phm, sizeof( PlayerHealthMsg ), DPNID_ALL_PLAYERS_GROUP, DPNSEND_NOLOOPBACK );
  375.  
  376.     // Check if the player is still alive (i.e. health above zero).
  377.     if( m_health > 0.0f )
  378.         return;
  379.  
  380.     // The player has been killed.
  381.     Kill();
  382.  
  383.     // Increment the player's death tally.
  384.     m_deaths += 1;
  385.  
  386.     // Send a player score update message for the fragged player.
  387.     PlayerScoreMsg psm1;
  388.     psm1.msgid = MSGID_PLAYER_SCORE;
  389.     psm1.dpnid = m_dpnid;
  390.     psm1.frags = m_frags;
  391.     psm1.deaths = m_deaths;
  392.     g_engine->GetNetwork()->Send( &psm1, sizeof( PlayerScoreMsg ), DPNID_ALL_PLAYERS_GROUP, DPNSEND_NOLOOPBACK );
  393.  
  394.     // Increment the attacking player's frag tally.
  395.     attacker->SetFrags( attacker->GetFrags() + 1 );
  396.  
  397.     // Send a player score update message for the bullet owner.
  398.     PlayerScoreMsg psm2;
  399.     psm2.msgid = MSGID_PLAYER_SCORE;
  400.     psm2.dpnid = attacker->GetID();
  401.     psm2.frags = attacker->GetFrags();
  402.     psm2.deaths = attacker->GetDeaths();
  403.     g_engine->GetNetwork()->Send( &psm2, sizeof( PlayerScoreMsg ), DPNID_ALL_PLAYERS_GROUP, DPNSEND_NOLOOPBACK );
  404. }
  405.  
  406. //-----------------------------------------------------------------------------
  407. // Kills the player.
  408. //-----------------------------------------------------------------------------
  409. void PlayerObject::Kill()
  410. {
  411.     // Indicate that the player is dying.
  412.     m_dying = true;
  413.  
  414.     // Clear the player's movment.
  415.     SetDrive( 0.0f );
  416.     SetStrafe( 0.0f );
  417.     SetFire( false );
  418.     Stop();
  419.  
  420.     // Clear the player's weapons.
  421.     ClearWeapons();
  422.  
  423.     // Stop the player from changing weapons.
  424.     m_changingWeapon = 0.0f;
  425.     m_weaponChanging = false;
  426.  
  427.     // Play the death animation.
  428.     PlayAnimation( ANIM_DEATH, 0.0f, false );
  429. }
  430.  
  431. //-----------------------------------------------------------------------------
  432. // Returns the player object's DirectPlay ID number.
  433. //-----------------------------------------------------------------------------
  434. DPNID PlayerObject::GetID()
  435. {
  436.     return m_dpnid;
  437. }
  438.  
  439. //-----------------------------------------------------------------------------
  440. // Returns the player object's name.
  441. //-----------------------------------------------------------------------------
  442. char *PlayerObject::GetName()
  443. {
  444.     return m_name;
  445. }
  446.  
  447. //-----------------------------------------------------------------------------
  448. // Sets the player object's health.
  449. //-----------------------------------------------------------------------------
  450. void PlayerObject::SetHealth( float health )
  451. {
  452.     m_health = health;
  453. }
  454.  
  455. //-----------------------------------------------------------------------------
  456. // Returns the player object's health.
  457. //-----------------------------------------------------------------------------
  458. float PlayerObject::GetHealth()
  459. {
  460.     return m_health;
  461. }
  462.  
  463. //-----------------------------------------------------------------------------
  464. // Sets the player object's dying flag.
  465. //-----------------------------------------------------------------------------
  466. void PlayerObject::SetDying( bool dying )
  467. {
  468.     m_dying = dying;
  469. }
  470.  
  471. //-----------------------------------------------------------------------------
  472. // Returns the player object's dying flag.
  473. //-----------------------------------------------------------------------------
  474. bool PlayerObject::GetDying()
  475. {
  476.     return m_dying;
  477. }
  478.  
  479. //-----------------------------------------------------------------------------
  480. // Sets the player object's viewing flag.
  481. //-----------------------------------------------------------------------------
  482. void PlayerObject::SetIsViewing( bool isViewing )
  483. {
  484.     m_isViewing = isViewing;
  485. }
  486.  
  487. //-----------------------------------------------------------------------------
  488. // Sets the player object's frag count.
  489. //-----------------------------------------------------------------------------
  490. void PlayerObject::SetFrags( unsigned long frags )
  491. {
  492.     m_frags = frags;
  493. }
  494.  
  495. //-----------------------------------------------------------------------------
  496. // Returns the player object's frag count.
  497. //-----------------------------------------------------------------------------
  498. unsigned long PlayerObject::GetFrags()
  499. {
  500.     return m_frags;
  501. }
  502.  
  503. //-----------------------------------------------------------------------------
  504. // Sets the player object's death count.
  505. //-----------------------------------------------------------------------------
  506. void PlayerObject::SetDeaths( unsigned long deaths )
  507. {
  508.     m_deaths = deaths;
  509. }
  510.  
  511. //-----------------------------------------------------------------------------
  512. // Returns the player object's death count.
  513. //-----------------------------------------------------------------------------
  514. unsigned long PlayerObject::GetDeaths()
  515. {
  516.     return m_deaths;
  517. }
  518.  
  519. //-----------------------------------------------------------------------------
  520. // Sets the player object's drive.
  521. //-----------------------------------------------------------------------------
  522. void PlayerObject::SetDrive( float drive )
  523. {
  524.     // Ignore if the player is dying (or dead)
  525.     if( m_dying == true )
  526.         return;
  527.  
  528.     if( drive == 0.0f )
  529.     {
  530.         if( m_drive != 0.0f && m_strafe == 0.0f )
  531.             PlayAnimation( ANIM_IDLE, 0.2f );
  532.     }
  533.     else if( m_drive == 0.0f && m_strafe == 0.0f )
  534.     {
  535.         if( drive == 1.0f )
  536.             PlayAnimation( ANIM_FORWARDS, 0.2f );
  537.         else
  538.             PlayAnimation( ANIM_BACKWARDS, 0.2f );
  539.     }
  540.  
  541.     m_drive = drive;
  542. }
  543.  
  544. //-----------------------------------------------------------------------------
  545. // Returns the player object's current drive.
  546. //-----------------------------------------------------------------------------
  547. float PlayerObject::GetDrive()
  548. {
  549.     return m_drive;
  550. }
  551.  
  552. //-----------------------------------------------------------------------------
  553. // Sets the player object's strafe.
  554. //-----------------------------------------------------------------------------
  555. void PlayerObject::SetStrafe( float strafe )
  556. {
  557.     // Ignore if the player is dying (or dead)
  558.     if( m_dying == true )
  559.         return;
  560.  
  561.     if( strafe == 0.0f )
  562.     {
  563.         if( m_strafe != 0.0f && m_drive == 0.0f )
  564.             PlayAnimation( ANIM_IDLE, 0.2f );
  565.     }
  566.     else if( m_strafe == 0.0f && m_drive == 0.0f )
  567.     {
  568.         if( strafe == 1.0f )
  569.             PlayAnimation( ANIM_RIGHT, 0.2f );
  570.         else
  571.             PlayAnimation( ANIM_LEFT, 0.2f );
  572.     }
  573.  
  574.     m_strafe = strafe;
  575. }
  576.  
  577. //-----------------------------------------------------------------------------
  578. // Returns the player object's current strafe.
  579. //-----------------------------------------------------------------------------
  580. float PlayerObject::GetStrafe()
  581. {
  582.     return m_strafe;
  583. }
  584.  
  585. //-----------------------------------------------------------------------------
  586. // Sets the player object's fire flag.
  587. //-----------------------------------------------------------------------------
  588. void PlayerObject::SetFire( bool fire )
  589. {
  590.     // Ignore if the player is dying (or dead)
  591.     if( m_dying == true )
  592.         return;
  593.  
  594.     m_fire = fire;
  595. }
  596.  
  597. //-----------------------------------------------------------------------------
  598. // Returns the player object's fire flag.
  599. //-----------------------------------------------------------------------------
  600. bool PlayerObject::GetFire()
  601. {
  602.     return m_fire;
  603. }
  604.  
  605. //-----------------------------------------------------------------------------
  606. // Changes weapon in either the given direction or to the given weapon.
  607. //-----------------------------------------------------------------------------
  608. void PlayerObject::ChangeWeapon( char change, char weapon )
  609. {
  610.     // Ignore if the player is dying (or dead)
  611.     if( m_dying == true )
  612.         return;
  613.  
  614.     // If the player is already changing weapons, then ingore this request.
  615.     if( m_changingWeapon > 0.0f )
  616.         return;
  617.  
  618.     // Store the player's current weapon.
  619.     m_oldWeapon = m_currentWeapon;
  620.  
  621.     // Check if the player is changing to a specific weapon.
  622.     if( change == 0 )
  623.     {
  624.         // Change to the weapon and ensure it is valid.
  625.         m_currentWeapon = weapon;
  626.         if( m_weapons[m_currentWeapon] == NULL )
  627.             m_currentWeapon = m_oldWeapon;
  628.         else if( m_weapons[m_currentWeapon]->GetValid() == false )
  629.             m_currentWeapon = m_oldWeapon;
  630.     }
  631.     else
  632.     {
  633.         // Loop through the weapons until the next valid weapon is found.
  634.         do
  635.         {
  636.             do
  637.             {
  638.                 m_currentWeapon += change;
  639.  
  640.                 if( m_currentWeapon < 0 )
  641.                     m_currentWeapon = 9;
  642.                 else if( m_currentWeapon > 9 )
  643.                     m_currentWeapon = 0;
  644.             }
  645.             while( m_weapons[m_currentWeapon] == NULL );
  646.         }
  647.         while( m_weapons[m_currentWeapon]->GetValid() == false );
  648.     }
  649.  
  650.     // Ensure the player actually changed to a different weapon.
  651.     if( m_oldWeapon == m_currentWeapon )
  652.         return;
  653.  
  654.     // Begin the weapon change process.
  655.     m_changingWeapon = 2.0f;
  656.  
  657.     // Send a weapon changing message.
  658.     NetworkMessage pwcm;
  659.     pwcm.msgid = MSGID_PLAYER_WEAPON_CHANGING;
  660.     pwcm.dpnid = g_engine->GetNetwork()->GetLocalID();
  661.     g_engine->GetNetwork()->Send( &pwcm, sizeof( NetworkMessage ), DPNID_ALL_PLAYERS_GROUP, DPNSEND_NOLOOPBACK );
  662. }
  663.  
  664. //-----------------------------------------------------------------------------
  665. // Indicates that this player is currently changing weapons.
  666. //-----------------------------------------------------------------------------
  667. void PlayerObject::WeaponChanging()
  668. {
  669.     m_weaponChanging = true;
  670. }
  671.  
  672. //-----------------------------------------------------------------------------
  673. // Indicates that this player has changed weapons to the given weapon.
  674. //-----------------------------------------------------------------------------
  675. void PlayerObject::WeaponChanged( char weapon )
  676. {
  677.     m_currentWeapon = weapon;
  678.     m_weaponChanging = false;
  679. }
  680.  
  681. //-----------------------------------------------------------------------------
  682. // Clears all the player object's weapons, except the first one.
  683. //-----------------------------------------------------------------------------
  684. void PlayerObject::ClearWeapons()
  685. {
  686.     // Invalidate all but the player's first weapon.
  687.     for( unsigned char w = 1; w < 10; w++ )
  688.         if( m_weapons[w] != NULL )
  689.             m_weapons[w]->SetValid( false );
  690.  
  691.     // Set the current weapon and weapon changing flags.
  692.     m_currentWeapon = 0;
  693.     m_changingWeapon = 0.0f;
  694.     m_weaponChanging = false;
  695. }
  696.  
  697. //-----------------------------------------------------------------------------
  698. // Sets the player object's view tilt (i.e. the rotation around the x axis).
  699. //-----------------------------------------------------------------------------
  700. void PlayerObject::SetViewTilt( float tilt )
  701. {
  702.     m_viewTilt = tilt;
  703. }
  704.  
  705. //-----------------------------------------------------------------------------
  706. // Returns the player object's view tilt (i.e. the rotation around the x axis).
  707. //-----------------------------------------------------------------------------
  708. float PlayerObject::GetViewTilt()
  709. {
  710.     return m_viewTilt;
  711. }
  712.  
  713. //-----------------------------------------------------------------------------
  714. // Returns the player object's eye point.
  715. //-----------------------------------------------------------------------------
  716. D3DXVECTOR3 PlayerObject::GetEyePoint()
  717. {
  718.     return GetTranslation() + m_viewPoint;
  719. }
  720.  
  721. //-----------------------------------------------------------------------------
  722. // Animation call back handler.
  723. //-----------------------------------------------------------------------------
  724. HRESULT CALLBACK PlayerObject::HandleCallback( THIS_ UINT Track, LPVOID pCallbackData )
  725. {
  726.     // Get a pointer to the callback data.
  727.     AnimationCallbackData *data = (AnimationCallbackData*)pCallbackData;
  728.  
  729.     // If the player is not touching the ground, then it can't make foot steps.
  730.     if( IsTouchingGround() == false )
  731.         return S_OK;
  732.  
  733.     // Check which foot caused the callback.
  734.     if( data->foot == 1 )
  735.     {
  736.         // Reset the step result.
  737.         m_stepResult.material = NULL;
  738.  
  739.         // Preform a ray intersection for the left foot. If it is succesful,
  740.         // then play the material's step sound.
  741.         if( g_engine->GetSceneManager()->RayIntersectScene( &m_stepResult, GetTranslation() + GetMesh()->GetReferencePoint( "rp_left_foot" )->GetTranslation(), D3DXVECTOR3( 0.0f, -1.0f, 0.0f ) ) == true )
  742.         {
  743.             if( ( (GameMaterial*)m_stepResult.material )->GetStepSound() != NULL )
  744.                 m_leftStepAudioPath->Play( ( (GameMaterial*)m_stepResult.material )->GetStepSound()->GetSegment() );
  745.         }
  746.     }
  747.     else
  748.     {
  749.         // Reset the step result.
  750.         m_stepResult.material = NULL;
  751.  
  752.         // Preform a ray intersection for the right foot. If it is succesful,
  753.         // then play the material's step sound.
  754.         if( g_engine->GetSceneManager()->RayIntersectScene( &m_stepResult, GetTranslation() + GetMesh()->GetReferencePoint( "rp_right_foot" )->GetTranslation(), D3DXVECTOR3( 0.0f, -1.0f, 0.0f ) ) == true )
  755.         {
  756.             if( ( (GameMaterial*)m_stepResult.material )->GetStepSound() != NULL )
  757.                 m_rightStepAudioPath->Play( ( (GameMaterial*)m_stepResult.material )->GetStepSound()->GetSegment() );
  758.         }
  759.     }
  760.  
  761.     return S_OK;
  762. }